
package com.iwhalecloud.bss.kite.cucc.service.job.cop.service;

import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.iwhalecloud.bss.kite.client.dto.DataResult;
import com.iwhalecloud.bss.kite.client.dto.rule.common.DataRuleResult;
import com.iwhalecloud.bss.kite.common.constant.ErrorConsts;
import com.iwhalecloud.bss.kite.common.constant.KeyConsts;
import com.iwhalecloud.bss.kite.common.constant.SymbolConsts;
import com.iwhalecloud.bss.kite.common.rule.check.ICheckService;
import com.iwhalecloud.bss.kite.common.util.*;
import com.iwhalecloud.bss.kite.cucc.client.api.customerOrderInformation.UserCenterClient;
import com.iwhalecloud.bss.kite.cucc.client.api.job.collectiongroup.IKiteBatchAcceptDetailService;
import com.iwhalecloud.bss.kite.cucc.client.api.job.cop.ICOPMemberCommitService;
import com.iwhalecloud.bss.kite.cucc.client.api.order.IOrderService;
import com.iwhalecloud.bss.kite.cucc.client.api.reception.ICustReceptionService;
import com.iwhalecloud.bss.kite.cucc.client.api.rule.check.ICuccCheckService;
import com.iwhalecloud.bss.kite.cucc.client.api.scene.ISceneCommitService;
import com.iwhalecloud.bss.kite.cucc.client.api.scene.operate.ICuccOperateSceneOfferInstService;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAccept;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAcceptDetail;
import com.iwhalecloud.bss.kite.cucc.client.dto.batch.KiteBatchAcceptDetailDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.cust.CuccContextCustDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.customerOrderInformation.QryGrpMemberListByMemReq;
import com.iwhalecloud.bss.kite.cucc.client.dto.customerOrderInformation.QryGrpUserDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosDTO;
import com.iwhalecloud.bss.kite.cucc.client.dto.pos.KitePosUserDTO;
import com.iwhalecloud.bss.kite.cucc.client.enumerate.UserDetailTagName;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalDcPublicConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalKeyConsts;
import com.iwhalecloud.bss.kite.cucc.common.constant.LocalServiceOfferConsts;
import com.iwhalecloud.bss.kite.cucc.common.util.CommonUtil;
import com.iwhalecloud.bss.kite.cucc.common.util.KiteAssert;
import com.iwhalecloud.bss.kite.cucc.dataservice.mapper.batch.KiteBatchAcceptDetailMapper;
import com.iwhalecloud.bss.kite.cucc.dataservice.mapper.batch.KiteBatchAcceptMapper;
import com.iwhalecloud.bss.kite.cucc.service.batch.BatchAcceptUtil;
import com.iwhalecloud.bss.kite.cucc.service.batch.enums.BatchAcceptStatusEnum;
import com.iwhalecloud.bss.kite.cucc.service.job.collectiongroup.StatusConst;
import com.iwhalecloud.bss.kite.cucc.service.util.CustInfoUtils;
import com.iwhalecloud.bss.kite.dataservice.cache.DcPublicCache;
import com.iwhalecloud.bss.kite.dataservice.cache.DcSystemParamCache;
import com.iwhalecloud.bss.kite.dataservice.cache.OfferCache;
import com.iwhalecloud.bss.kite.manager.api.IOperateSceneInstService;
import com.iwhalecloud.bss.kite.manager.api.IQuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.enums.ActionType;
import com.iwhalecloud.bss.kite.manager.enums.InstType;
import com.iwhalecloud.bss.kite.manager.inst.*;
import com.iwhalecloud.bss.kite.manager.scene.service.QuerySceneInstService;
import com.iwhalecloud.bss.kite.manager.scene.service.operate.OperateChangeService;
import com.iwhalecloud.bss.kite.manager.util.KiteTransactionUtils;
import com.ztesoft.bss.common.bo.LoginInfo;
import com.ztesoft.bss.common.exception.BssException;
import com.ztesoft.bss.common.util.ContextUtil;
import com.ztesoft.bss.common.util.SpringUtil;
import com.ztesoft.bss.rul.core.client.dto.common.RuleCommonParam;
import com.ztesoft.common.logger.api.ZLogger;
import com.ztesoft.common.logger.factory.ZLoggerFactory;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import tk.mybatis.mapper.entity.Example;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @author lyx
 * @version V1.0
 * @Description:
 * @date 2021/9/10
 * @Package com.iwhalecloud.bss.kite.cucc.service.job.cop.service
 */
@Service
@RequiredArgsConstructor
public class COPMemberCommitService implements ICOPMemberCommitService {

    private static final ZLogger LOGGER = ZLoggerFactory.getLogger(COPMemberCommitService.class, KeyConsts.LOG_MODULE);

    private final KiteBatchAcceptDetailMapper kiteBatchAcceptDetailMapper;

    private final IQuerySceneInstService querySceneInstService;

    private final ICheckService checkService;

    private final ICustReceptionService custReceptionService;

    private final KiteBatchAcceptMapper kiteBatchAcceptMapper;

    private final ICuccOperateSceneOfferInstService cuccOperateSceneOfferInstService;

    private final IOrderService orderService;

    private final OperateChangeService operateChangeService;

    private final IOperateSceneInstService operateSceneInstService;

    @Autowired
    IKiteBatchAcceptDetailService kiteBatchAcceptDetailService;

    @Override
    public void addMember() {
        /*String num = DcSystemParamCache.getDcParamVal("COP_BATCH_ACCEPT_JOB_NUM");
        if (KiteStringUtils.isEmpty(num)) {
            num = "50";
        }
        List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails = kiteBatchAcceptDetailMapper
            .listExecuteDetailsByStatus(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_6100, StatusConst.NOT_STATUSCD, Integer.parseInt(num));*/
        List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails = this.getBatchAcceptDetails(Lists.newArrayList(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_6100));
        if (KiteListUtils.isEmpty(kiteBatchAcceptDetails)) {
            return;
        }
        LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(kiteBatchAcceptDetails.get(0));
        ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);

        String custId = kiteBatchAcceptDetails.get(0).getCustId();
        String provinceNbr = kiteBatchAcceptDetails.get(0).getProvinceId();
        CuccContextCustDTO contextCust = CustInfoUtils.getCustInfo(custId, provinceNbr, "0");

        this.executeCheckRule(contextCust, kiteBatchAcceptDetails);
        // 校验通过的才需要转单
        kiteBatchAcceptDetails = kiteBatchAcceptDetails.stream()
            .filter(detailDTO -> KiteStringUtils.equals(detailDTO.getCheckStatus(), "1200")).collect(Collectors.toList());
        if (KiteListUtils.isEmpty(kiteBatchAcceptDetails)) {
            return;
        }
        this.initInstAndCommit(contextCust, kiteBatchAcceptDetails, kiteBatchAcceptDetails.get(0).getSceneInstId());
    }

    @Override
    public void delMember() {
        /*String num = DcSystemParamCache.getDcParamVal("COP_BATCH_ACCEPT_JOB_NUM");
        if (KiteStringUtils.isEmpty(num)) {
            num = "50";
        }
        List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails = kiteBatchAcceptDetailMapper
            .listExecuteDetailsByStatus(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_6200, StatusConst.NOT_STATUSCD, Integer.parseInt(num));*/

        List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails = this.getBatchAcceptDetails(Lists.newArrayList(LocalKeyConsts.BATCH_ACCEPT_IMPORT_TYPE_6200));
        if (KiteListUtils.isEmpty(kiteBatchAcceptDetails)) {
            return;
        }
        LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(kiteBatchAcceptDetails.get(0));
        ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
        String custId = kiteBatchAcceptDetails.get(0).getCustId();
        String provinceNbr = kiteBatchAcceptDetails.get(0).getProvinceId();
        CuccContextCustDTO contextCust = CustInfoUtils.getCustInfo(custId, provinceNbr, "0");

        this.executeCheckRule(contextCust, kiteBatchAcceptDetails);
        // 校验通过的才需要转单
        kiteBatchAcceptDetails = kiteBatchAcceptDetails.stream()
            .filter(detailDTO -> KiteStringUtils.equals(detailDTO.getCheckStatus(), "1200"))
            .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(kiteBatchAcceptDetails)) {
            return;
        }
        this.initInstAndCommit(contextCust, kiteBatchAcceptDetails, kiteBatchAcceptDetails.get(0).getSceneInstId());
    }

    private void executeCheckRule(CuccContextCustDTO contextCust, List<KiteBatchAcceptDetailDTO> kiteBatchAcceptDetails) {
        if (KiteListUtils.isEmpty(kiteBatchAcceptDetails)) {
            return;
        }
        // 创建执行线程类集合
        ExecutorService executorService = null;
        List<Callable<Boolean>> tasks = new ArrayList<>();
        kiteBatchAcceptDetails.stream()
            .filter(kiteBatchAcceptDetail -> kiteBatchAcceptDetail.getOfferInstId() == null)
            .forEach(kiteBatchAcceptDetail -> tasks.add(() -> {
                try {
                    LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(kiteBatchAcceptDetail);
                    ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
                    // 如果存在校验状态为新建（1000）
                    if (KiteStringUtils.equals(kiteBatchAcceptDetail.getCheckStatus(), "1000")) {
                        checkCopMember(contextCust, kiteBatchAcceptDetail);
                    }
                }
                catch (Exception e) {
//                    e.printStackTrace();
                    kiteBatchAcceptDetailService
                        .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(),
                            ExceptionUtils.getStackTrace(e), kiteBatchAcceptDetail.getBatchId());
                }
                return true;
            }));

        try {
            // 1、并发执行校验
            ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("executeCheckRule-thread-pool-%d")
                .build();
            executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 6,
                Runtime.getRuntime().availableProcessors() + 6, 5000L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<>(300), threadFactory);
            executorService.invokeAll(tasks);
        }
        catch (InterruptedException e) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut(e, "校验失败");
        }
        finally {
            if (Objects.nonNull(executorService)) {
                executorService.shutdown();
            }
        }
    }

    private void checkCopMember(CuccContextCustDTO contextCust, KiteBatchAcceptDetailDTO kiteBatchAcceptDetail) {
        List<KiteAttr> kiteAttrList = JSONObject.parseArray(kiteBatchAcceptDetail.getAttrJson(), KiteAttr.class);
        String memberNum = kiteAttrList.stream()
            .filter(kiteAttr -> KiteStringUtils.equals("serialNumber", kiteAttr.getFieldName())).findFirst()
            .map(KiteAttr::getValue).orElse("");
        //(1)成员号码为11位数字，如果不是则修改校验状态为校验失败（1100），校验结果为“业务号码不正确，请检查”；
        if (KiteStringUtils.isEmpty(memberNum) || !KiteStringUtils.isNum(memberNum) || memberNum.length() != 11) {
            kiteBatchAcceptDetail.setCheckStatus("1100");
            kiteBatchAcceptDetail.setCheckResult("业务号码不正确，请检查");
            kiteBatchAcceptDetailService
                .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(), "业务号码不正确，请检查",
                    kiteBatchAcceptDetail.getBatchId());
            return;
        }

        String sceneInstId = kiteBatchAcceptDetail.getSceneInstId();
        String custId = kiteBatchAcceptDetail.getCustId();
        KiteSceneInst kiteSceneInst = querySceneInstService.getSceneInst(sceneInstId, custId);
        String business_number = querySceneInstService.getCommonAttrValue(sceneInstId, "business_number");

        //(2)校验是否可以加入。如果返回数据为空，修改校验状态为校验失败（1100），校验结果为“成员业务号码：***********,不存在用户信息，请检查”；
        UserCenterClient userCenterClient = SpringUtil.getBean(UserCenterClient.class);
        try {
            // 此方法会抛异常，外层捕获处理
            List<Map<String, Object>> groupUserInfoDetails = userCenterClient.qryGroupUserInfoDetails(kiteBatchAcceptDetail.getSceneInstId(), memberNum, "", "0000", "T");
            if (KiteListUtils.isEmpty(groupUserInfoDetails)) {
                kiteBatchAcceptDetail.setCheckStatus("1100");
                kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + ",不存在用户信息，请检查");
                kiteBatchAcceptDetailService
                    .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(),
                        "成员业务号码：" + memberNum + ",不存在用户信息，请检查", kiteBatchAcceptDetail.getBatchId());
                return;
            }
        }
        catch (BssException e) {
            e.printStackTrace();
            kiteBatchAcceptDetail.setCheckStatus("1100");
            kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + ",不存在用户信息，请检查");
            kiteBatchAcceptDetailService
                .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(),
                    "成员业务号码：" + memberNum + ",不存在用户信息，请检查", kiteBatchAcceptDetail.getBatchId());
            return;
        }
        //(3)调【成员信息查群组成员列表信息/json_GEuserCenter_SalBusaGrpMemberSerApi_qryGrpMemberListByMem】查已加入的群组，如果关系类型编码RELATION_TYPE_CODE存在COP业务集团类型（具体编码值待定），则不允许重复加入，修改校验状态为校验失败（1100），校验结果为“该成员已加入群组”；
        // 3、校验是否已加入群组
        QryGrpMemberListByMemReq qryGrpMemberListByMemReq = new QryGrpMemberListByMemReq();
        qryGrpMemberListByMemReq.setFinishState("G");
        qryGrpMemberListByMemReq.setCurPage(1L);
        qryGrpMemberListByMemReq.setPageSize(10L);
        qryGrpMemberListByMemReq.setQueryOldSystem("2");
        qryGrpMemberListByMemReq.setMemSerialNumber(memberNum);

        //Map<String, String> memSerialNumberMap = new HashMap<>();
        //memSerialNumberMap.put("MEM_SERIAL_NUMBER", memberNum);
        //qryGrpMemberListByMemReq.setMemSerialNumbers(Lists.newArrayList(memSerialNumberMap));

        PageInfo<QryGrpUserDTO> qryGrpUserDTO = userCenterClient.qryGrpMemberListByMem(qryGrpMemberListByMemReq);

        String copRelationTypeCodes = DcPublicCache.getCodea(LocalDcPublicConsts.DC_20210911001, "copRelationTypeCode");
        if (KiteStringUtils.equals(kiteSceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COP_MEMBER_JOIN)) {
            if (qryGrpUserDTO.getTotal() > 0 && qryGrpUserDTO.getList().stream().anyMatch(grpUser -> {
                return (!KiteStringUtils.isEmpty(copRelationTypeCodes)
                    && Lists.newArrayList(copRelationTypeCodes.split(SymbolConsts.COMMA)).contains(grpUser.getRelationTypeCode())
                    && KiteStringUtils.equals(grpUser.getSerialNumber(), business_number));
            })) {
                kiteBatchAcceptDetail.setCheckStatus("1100");
                kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + ",已加入群组，请检查");
                kiteBatchAcceptDetailService
                    .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(), "成员业务号码：" + memberNum + ",已加入群组，请检查",
                        kiteBatchAcceptDetail.getBatchId());
                return;
            }
        }
        else {
            String finalMemberNum = memberNum;
            if (qryGrpUserDTO.getTotal() == 0 || !qryGrpUserDTO.getList().stream().anyMatch(grpUser -> {
                return (!KiteStringUtils.isEmpty(copRelationTypeCodes)
                    && Lists.newArrayList(copRelationTypeCodes.split(SymbolConsts.COMMA)).contains(grpUser.getRelationTypeCode())
                    && KiteStringUtils.equals(grpUser.getSerialNumber(), business_number));
            })) {
                kiteBatchAcceptDetail.setCheckStatus("1100");
                kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + finalMemberNum + ",该成员没有加入群组，请检查");

                kiteBatchAcceptDetailService
                    .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(), "成员业务号码：" + finalMemberNum
                            + ",该成员没有加入群组，请检查",
                        kiteBatchAcceptDetail.getBatchId());
                return;
            }
        }


        //(5)校验成功修改校验状态为校验成功（1200），校验结果为“校验成功”；
        kiteBatchAcceptDetail.setCheckStatus("1200");
        kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + ",校验成功");

        kiteBatchAcceptDetailService
            .updateKiteBatchAcceptDetailCheckStatus("1200", kiteBatchAcceptDetail.getDetailId(), "成员业务号码：" + memberNum + ",校验成功",
                kiteBatchAcceptDetail.getBatchId());
    }

    public static <V> Callable<V> wrapLoginInfoAndTrans(KiteBatchAcceptDetailDTO kiteBatchAcceptDetail, Callable<V> callable) {
        LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(kiteBatchAcceptDetail);
        String transactionId = KiteTransactionUtils.getTransactionId();
        return () -> {
            KiteTransactionUtils.setTransactionId(transactionId);
            ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
            try {
                return callable.call();
            }
            finally {
                ContextUtil.removeThreadLocal();
            }
        };
    }

    private RuleCommonParam getRuleParam(String sceneInstId, String memberNum, CuccContextCustDTO contextCust) {
        RuleCommonParam param = new RuleCommonParam();
        param.setLanId(ContextUtil.getLoginInfo().getUserInfo().getPostProvinceNbr());
        param.setOrgId(ContextUtil.getSimpleLoginInfo().getOrgId().toString());
        param.setRegionId(ContextUtil.getLoginInfo().getUserInfo().getPostRegionId().toString());
        param.setSysUserId(ContextUtil.getUserId().toString());
        param.setCustId(contextCust.getCustId());
        if (KiteStringUtils.isNotEmpty(sceneInstId)) {
            // 受理完成或者放弃办理时，场景实例已经清掉，但上下文中的场景实例id还是之前的，会造成下面取不到场景，这里取不到直接捕捉
            try {
                QuerySceneInstService query = SpringUtil.getBean(QuerySceneInstService.class);
                KiteSceneInst sceneInst = query.getSceneInst(sceneInstId);
                if (null != sceneInst) {
                    param.setAcceptMode(sceneInst.getAcceptMode());
                }
            }
            catch (Exception e) {
                LOGGER.error(ErrorConsts.SYSTEM_ERROR.getErrorCode(), e, e.getMessage());
            }
        }
        com.ztesoft.bss.rul.core.client.dto.common.ContextCustDTO ruleCust = new com.ztesoft.bss.rul.core.client.dto.common.ContextCustDTO();
        ruleCust.setCustId(contextCust.getCustId());
        ruleCust.setCustName(contextCust.getCustName());
        ruleCust.setCertType(contextCust.getCertType());
        ruleCust.setCertNum(contextCust.getCertNum());
        ruleCust.setLanId(contextCust.getLanId());
        ruleCust.setRegionId(contextCust.getRegionId());
        ruleCust.setContactName(contextCust.getContactName());
        ruleCust.setMobilePhone(contextCust.getMobilePhone());
        param.setCustInfo(ruleCust);

        Map<String, Object> params = param.getParams();
        if (params == null) {
            // MapUtils.EMPTY_MAP底层UnmodifiableMap，调用put方法会直接抛异常
            params = new HashMap<>();
        }
        params.put("memSerialNum", memberNum);
        params.put("areaLanId", ContextUtil.getLandId());
        param.setParams(params);

        return param;
    }

    private Boolean initInstAndCommit(CuccContextCustDTO contextCust, List<KiteBatchAcceptDetailDTO> detailDTOS, String sceneInstId) {
        DataResult<String> result = new DataResult<>();
        if (KiteListUtils.isEmpty(detailDTOS)) {
            return Boolean.TRUE;
        }
        try {
            if (KiteStringUtils.isBlank(KiteTransactionUtils.getTransactionId())) {
                String transactionId = KiteTransactionUtils.genTransactionId();
                KiteTransactionUtils.setTransactionId(transactionId);
            }
            LoginInfo loginInfo = BatchAcceptUtil.getLoginInfo(detailDTOS.get(0));
            ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
            // 重新加载一次场景到缓存中（防止缓存过去，多线程中每个线程都还原）
            querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
            // 未实例化的实例化到场景中
            List<KiteBatchAcceptDetail> kiteBatchAcceptDetails = KiteBeanUtils
                .copyPropsForList(detailDTOS, KiteBatchAcceptDetail.class);
            // 创建执行线程类集合
            ExecutorService executorService = null;
            List<Callable<Boolean>> tasks = new ArrayList<>();
            detailDTOS.stream()
                .filter(kiteBatchAcceptDetail -> kiteBatchAcceptDetail.getOfferInstId() == null)
                .forEach(kiteBatchAcceptDetail -> tasks.add(FunctionWrapper.wrapLoginInfoAndTrans(() -> {
                    try {
                        String offerInstId = instantiate(sceneInstId, kiteBatchAcceptDetail, contextCust);
                        kiteBatchAcceptDetail.setOfferInstId(Long.parseLong(offerInstId));
                        return Boolean.TRUE;
                    }
                    catch (Exception e) {
                        kiteBatchAcceptDetail.setStatusCd("1100");
                        kiteBatchAcceptDetail.setDealResult(ExceptionUtils.getStackTrace(e));
                        return Boolean.FALSE;
                    }
                })));

            try {
                ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("instantiate-thread-pool-%d")
                    .build();
                executorService = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 6,
                    Runtime.getRuntime().availableProcessors() + 6, 5000L, TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(300), threadFactory);
                executorService.invokeAll(tasks);
            }
            catch (InterruptedException e) {
                ErrorConsts.BUSI_COMMON_ERROR.throwOut(e, "初始化失败");
            }
            finally {
                if (Objects.nonNull(executorService)) {
                    executorService.shutdown();
                }
            }
            // 将offerInstId写入表中
            TransactionUtils.executeNew(() -> kiteBatchAcceptDetails.forEach(kiteBatchAcceptDetail -> {
                if (Objects.isNull(kiteBatchAcceptDetail.getOfferInstId())) {
                    return;
                }
                Example example = new Example(KiteBatchAcceptDetail.class);
                example.createCriteria().andEqualTo("batchId", kiteBatchAcceptDetail.getBatchId())
                    .andEqualTo("detailId", kiteBatchAcceptDetail.getDetailId());
                kiteBatchAcceptDetailMapper.updateByExampleSelective(
                    new KiteBatchAcceptDetail().setOfferInstId(kiteBatchAcceptDetail.getOfferInstId()), example);
            }));

            // 检查数据如果没有一条数据实例化成功，则不需要掉转单服务
            if (detailDTOS.stream().noneMatch(detailDTO -> KiteStringUtils.equals(detailDTO.getStatusCd(), "1000"))) {
                result.setResultCode("9999");
                result.setResultObject("实例化失败：" + detailDTOS.get(0).getDealResult());
                return Boolean.FALSE;
            }

            ContextUtil.setLoginInfo2LoginInfoThreadLocal(loginInfo);
            String staffId = loginInfo.getStaffId().toString();
            String orgId = loginInfo.getOrgInfo().getOrgId().toString();
            // 重新加载一次场景到缓存中（防止缓存过去，多线程中每个线程都还原）
            querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());

            // 提交场景
            ISceneCommitService sceneCommitService = SpringUtil.getBean(ISceneCommitService.class);
            result = sceneCommitService.commitScene(sceneInstId, staffId, orgId, contextCust, false, false);
        }
        catch (Exception e) {
//            e.printStackTrace();
            result.setResultObject(ExceptionUtils.getStackTrace(e));
        }
        finally {
            LocalDateTime now = LocalDateTime.now();
            DataResult<String> finalResult = result;
            TransactionUtils.executeNew(() -> {
                if (KiteStringUtils.isEqual(ErrorConsts.SUCCESS.getCode(), finalResult.getResultCode())) {
                    // 成功
                    detailDTOS.forEach(detailDTO -> {
                        KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail()
                            .setExtOrderId(finalResult.getResultObject())
                            .setDealResult("批量处理成功，订单号：" + finalResult.getResultObject()).setStatusCd("1200")
                            .setStatusDate(now);
                        detailDTO.setStatusCd("1200");
                        Example example = new Example(KiteBatchAcceptDetail.class);
                        example.createCriteria().andEqualTo("batchId", detailDTO.getBatchId())
                            .andEqualTo("detailId", detailDTO.getDetailId());
                        kiteBatchAcceptDetailMapper.updateByExampleSelective(detail, example);
                    });
                }
                else {
                    // 失败
                    detailDTOS.forEach(detailDTO -> {
                        KiteBatchAcceptDetail detail = new KiteBatchAcceptDetail()
                            .setDealResult(finalResult.getResultObject()).setStatusCd("1100").setStatusDate(now);
                        detailDTO.setStatusCd("1100");
                        Example example = new Example(KiteBatchAcceptDetail.class);
                        example.createCriteria().andEqualTo("batchId", detailDTO.getBatchId())
                            .andEqualTo("detailId", detailDTO.getDetailId());
                        kiteBatchAcceptDetailMapper.updateByExampleSelective(detail, example);
                    });
                }
            });
            ContextUtil.removeThreadLocal();
        }
        return Boolean.TRUE;
    }

    public String instantiate(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail, CuccContextCustDTO contextCust) {
        KiteSceneInst sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        if (KiteStringUtils.equals(sceneInst.getServiceOfferId(), LocalServiceOfferConsts.SERVICE_OFFER_COP_MEMBER_JOIN)) {
            return this.initJoinOfferInst(sceneInstId, kiteBatchAcceptDetail, contextCust);
        }
        else {
            return this.initQuitOfferInst(sceneInstId, kiteBatchAcceptDetail, contextCust);
        }
    }

    public String initJoinOfferInst(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail, CuccContextCustDTO contextCust) {
        KiteAssert.notNull(kiteBatchAcceptDetail, ErrorConsts.BUSI_COMMON_ERROR, "该记录不存在");
        KiteSceneInst sceneInst = null;
        if (Objects.nonNull(contextCust)) {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        }
        else {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        }
        String serviceOfferId = sceneInst.getServiceOfferId();
        String provinceNbr = sceneInst.getProvinceNbr();

        List<KiteAttr> kiteAttrs = JSONObject.parseArray(kiteBatchAcceptDetail.getAttrJson(), KiteAttr.class);
        String memberNum = "";
        if (KiteListUtils.isNotEmpty(kiteAttrs)) {
            memberNum = kiteAttrs.stream().filter(kiteAttr -> "serialNumber".equals(kiteAttr.getFieldName())).findAny()
                .map(KiteAttr::getValue).orElse("");
        }
        List<KiteInst> memOfferInsts = this.querySceneInstService.listInsts(sceneInstId, Lists.newArrayList(InstType.MEM_OFFER_INST)).stream().filter(offerInst -> {
            return KiteStringUtils.equalsAny(offerInst.getActionType().name(), ActionType.K.name(), ActionType.A.name(), ActionType.M.name());
        }).collect(Collectors.toList());
        if (KiteStringUtils.equals(serviceOfferId, LocalServiceOfferConsts.SERVICE_OFFER_COP_MEMBER_JOIN) && KiteListUtils.isEmpty(memOfferInsts)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("模板实例为空，批量提交处理失败");
        }
        String offerId = memOfferInsts.get(0).getSpecId();
        UserCenterClient userCenterClient = SpringUtil.getBean(UserCenterClient.class);
        List<Map<String, Object>> userInfoList = userCenterClient
            .qryGroupUserInfoDetails(sceneInstId, memberNum, "", "0000", "T");
        if (KiteListUtils.isEmpty(userInfoList)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("成员业务号码：" + memberNum + ",不存在用户信息，请检查");
        }
        //TODO (4)调规则校验是否有成员加入、成员退出在途单，有在途单不允许进行成员加入，修改校验状态为校验失败（1100），校验结果为“已存在在途单，不允许重复操作”；
        RuleCommonParam ruleCommonParam = getRuleParam(sceneInstId, memberNum, contextCust);
        ruleCommonParam.getParams().put("delMemList", this.converKeyToUpperCase(userInfoList));
        DataRuleResult dataRuleResult = SpringUtil.getBean(ICuccCheckService.class).cuccCheckOnOrderPreview(sceneInstId,
            contextCust.getCustId(), ruleCommonParam);
        if (!KiteStringUtils.equals(dataRuleResult.getResultCode(), "0000") && !KiteStringUtils.equals(dataRuleResult.getResultCode(), "0")) {
            kiteBatchAcceptDetail.setCheckStatus("1100");
            kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + "已存在在途单，不允许重复操作");

            kiteBatchAcceptDetailService
                .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(),
                    "成员业务号码：" + memberNum + "已存在在途单，不允许重复操作", kiteBatchAcceptDetail.getBatchId());
            return null;
        }

        /*Map<String, Object> memOrderInfo = orderService
            .getChangeOriginOrder(null, contextCust.getCustId(), memberNum, provinceNbr, ContextUtil.getLandId(), staffCode);
        KitePosDTO memKitePosDTO = JSONObject
            .toJavaObject(JSON.parseObject(JSON.toJSONString(memOrderInfo)), KitePosDTO.class);
        if (KiteObjectUtils.isEmpty(memKitePosDTO) || KiteListUtils.isEmpty(memKitePosDTO.getUsers())) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("成员业务号码：" + memberNum + "，获取用户信息失败，请检查");
        }*/
        String offerInstId;
        if (Objects.nonNull(kiteBatchAcceptDetail.getOfferInstId())) {
            // 如果offerInstId在表中存在说明已经实例化过
            offerInstId = kiteBatchAcceptDetail.getOfferInstId().toString();
        }
        else {
            // 增加销售品实例
            offerInstId = addOfferInst(sceneInstId, offerId, sceneInst, contextCust, null, userInfoList).getOfferInstId();
        }
        return offerInstId;
    }

    public String initQuitOfferInst(String sceneInstId, KiteBatchAcceptDetail kiteBatchAcceptDetail, CuccContextCustDTO contextCust) {
        KiteAssert.notNull(kiteBatchAcceptDetail, ErrorConsts.BUSI_COMMON_ERROR, "该记录不存在");
        KiteSceneInst sceneInst = null;
        if (Objects.nonNull(contextCust)) {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId, contextCust.getCustId());
        }
        else {
            sceneInst = querySceneInstService.getSceneInst(sceneInstId);
        }
        String provinceNbr = sceneInst.getProvinceNbr();
        String offerInstId;
        if (Objects.nonNull(kiteBatchAcceptDetail.getOfferInstId())) {
            // 如果offerInstId在表中存在说明已经实例化过
            offerInstId = kiteBatchAcceptDetail.getOfferInstId().toString();
        }
        else {
            offerInstId = delOfferInst(sceneInstId, provinceNbr, null, sceneInst, kiteBatchAcceptDetail, contextCust).getOfferInstId();
        }
        return offerInstId;
    }

    private KiteOfferInst addOfferInst(String sceneInstId, String offerId, KiteSceneInst sceneInst,
        CuccContextCustDTO contextCust, KitePosDTO memKitePosDTO, List<Map<String, Object>> userInfoList) {
        KiteOfferInst kiteOfferInst = cuccOperateSceneOfferInstService
            .addMemOfferInst(sceneInstId, sceneInst.getRootInstId(), offerId, "2004010", contextCust.getCustId(),
                ContextUtil.getUserId().toString()).getResultObject();

        for (Map<String, Object> stringObjectMap : userInfoList) {
            stringObjectMap.put("instance_id", CommonUtil.getInstanceId(LocalKeyConsts.YH_INST_CODE, SeqUtils.getNext("SEQ_USER_ID")));

            String memSerialNum = KiteMapUtils.getString(stringObjectMap, "serial_number");

            //200002981
            List<KiteProdInst> prodInsts = this.querySceneInstService.listProdInstsFromOfferInst(contextCust.getCustId(), kiteOfferInst.getOfferInstId());
            if (!KiteListUtils.isEmpty(prodInsts)) {
                KiteProdInst prodInst = prodInsts.get(0);

                KiteAttr serialNumAttr = new KiteAttr();
                serialNumAttr.setValue(memSerialNum);
                serialNumAttr.setFieldName("200002981");
                serialNumAttr.setShowType("E");
                prodInst.setAttr(serialNumAttr);
                operateSceneInstService.addInst(sceneInstId, prodInst);
            }
        }

        // 用户信息作为属性保存，转单使用
        KiteAttr userAttr = new KiteAttr();
        userAttr.setValue(JSONObject.toJSONString(userInfoList));
        userAttr.setFieldName("userInfo");
        userAttr.setShowType("E");
        operateSceneInstService.setOfferInstAttr(sceneInstId, kiteOfferInst.getOfferInstId(), userAttr);

        return kiteOfferInst;
    }

    private KiteOfferInst delOfferInst(String sceneInstId, String provinceNbr, String offerId, KiteSceneInst sceneInst,
        KiteBatchAcceptDetail kiteBatchAcceptDetail, CuccContextCustDTO contextCust) {
        List<KiteAttr> kiteAttrs = JSONObject.parseArray(kiteBatchAcceptDetail.getAttrJson(), KiteAttr.class);
        String memberNum = "";
        if (KiteListUtils.isNotEmpty(kiteAttrs)) {
            memberNum = kiteAttrs.stream().filter(kiteAttr -> "serialNumber".equals(kiteAttr.getFieldName())).findAny()
                .map(KiteAttr::getValue).orElse("");
        }
        UserCenterClient userCenterClient = SpringUtil.getBean(UserCenterClient.class);
        List<Map<String, Object>> userInfoList = userCenterClient
            .qryGroupUserInfoDetails(sceneInstId, memberNum, "", "0000", "T");
        if (KiteListUtils.isEmpty(userInfoList)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("成员业务号码：" + memberNum + ",不存在用户信息，请检查");
        }
        userInfoList.get(0).put("instance_id", KiteStringUtils.join(LocalKeyConsts.YH_INST_CODE, SeqUtils.getNext("SEQ_USER_ID")));

        //TODO (4)调规则校验是否有成员加入、成员退出在途单，有在途单不允许进行成员加入，修改校验状态为校验失败（1100），校验结果为“已存在在途单，不允许重复操作”；
        RuleCommonParam ruleCommonParam = getRuleParam(sceneInstId, memberNum, contextCust);
        ruleCommonParam.getParams().put("delMemList", this.converKeyToUpperCase(userInfoList));
        DataRuleResult dataRuleResult = SpringUtil.getBean(ICuccCheckService.class).cuccCheckOnOrderPreview(sceneInstId,
            contextCust.getCustId(), ruleCommonParam);
        if (!KiteStringUtils.equals(dataRuleResult.getResultCode(), "0000") && !KiteStringUtils.equals(dataRuleResult.getResultCode(), "0")) {
            kiteBatchAcceptDetail.setCheckStatus("1100");
            kiteBatchAcceptDetail.setCheckResult("成员业务号码：" + memberNum + "已存在在途单，不允许重复操作");

            kiteBatchAcceptDetailService
                .updateKiteBatchAcceptDetailCheckStatus("1100", kiteBatchAcceptDetail.getDetailId(),
                    "成员业务号码：" + memberNum + "已存在在途单，不允许重复操作", kiteBatchAcceptDetail.getBatchId());
            return null;
        }

        String memUserId = KiteMapUtils.getString(userInfoList.get(0), "user_id");

        String primaryUserId = null;
        List<KitePosUserDTO> mainUsers = this.querySceneInstService.getExtParameterValue(sceneInstId, "serialNumber");
        if (!KiteListUtils.isEmpty(mainUsers)) {
            primaryUserId = mainUsers.get(0).getUserId();
        }

        Map<String, Object> memGoodsInfoOfUser = userCenterClient.queryMemberUserDetail(Boolean.FALSE, primaryUserId, memUserId, Lists
            .newArrayList(UserDetailTagName.USER_DISCNT, UserDetailTagName.USER_DISCNT_ITEM,UserDetailTagName.USER_GOODS));
        if (KiteMapUtils.isEmpty(memGoodsInfoOfUser)) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("成员业务号码：" + memberNum + ",未订购成员商品，请检查");
        }
        List<Map<String, Object>> memGoodsList = (List<Map<String, Object>>) memGoodsInfoOfUser.get("USER_GOODS_INFOS");
        if (KiteListUtils.isEmpty(memGoodsList) ||
            !memGoodsList.stream().anyMatch(goods -> KiteStringUtils.equals(OfferCache.get(KiteMapUtils.getString(goods, "GOODS_ID")).getCateId(), "2004010"))) {
            ErrorConsts.BUSI_COMMON_ERROR.throwOut("成员业务号码：" + memberNum + ",未订购成员商品，请检查");
        }
        // 取成员商品
        Map<String, Object> memGoodsMap = memGoodsList.stream().filter(goods -> KiteStringUtils.equals(OfferCache.get(KiteMapUtils.getString(goods, "GOODS_ID")).getCateId(), "2004010")).findAny().orElse(MapUtils.EMPTY_MAP);
        // 添加实例
        KiteOfferInst kiteOfferInst = cuccOperateSceneOfferInstService
            .addMemOfferInst(sceneInstId, sceneInst.getRootInstId(), KiteMapUtils.getString(memGoodsMap, "GOODS_ID"), "2004010",
                contextCust.getCustId(), ContextUtil.getUserId().toString())
            .getResultObject();

        // 用户信息作为属性保存，转单使用
        KiteAttr userAttr = new KiteAttr();
        userAttr.setValue(JSONObject.toJSONString(userInfoList));
        userAttr.setFieldName("userInfo");
        userAttr.setShowType("E");
        kiteOfferInst.setAttr(userAttr);
        // 设置为删除
        operateChangeService.setDeleteInstChange(sceneInst, kiteOfferInst, false, null, "");
        kiteOfferInst.setExtOfferInstId(KiteMapUtils.getString(memGoodsMap, "GOODS_ITEM_ID"));
        kiteOfferInst.setActionType(ActionType.D);
        kiteOfferInst.setOwnerCustId(contextCust.getCustId());
        kiteOfferInst.setUseCustId(contextCust.getCustId());
        kiteOfferInst.setOriginalActionType(ActionType.K);
        operateSceneInstService.addInst(sceneInstId, kiteOfferInst);

        //200002981
        List<KiteProdInst> prodInsts = this.querySceneInstService.listProdInstsFromOfferInst(contextCust.getCustId(), kiteOfferInst.getOfferInstId());
        if (!KiteListUtils.isEmpty(prodInsts)) {
            KiteProdInst prodInst = prodInsts.get(0);

            KiteAttr serialNumAttr = new KiteAttr();
            serialNumAttr.setValue(memberNum);
            serialNumAttr.setFieldName("200002981");
            serialNumAttr.setShowType("E");
            prodInst.setAttr(serialNumAttr);

            prodInst.setActionType(ActionType.D);
            prodInst.setOwnerCustId(contextCust.getCustId());
            prodInst.setUseCustId(contextCust.getCustId());
            prodInst.setOriginalActionType(ActionType.K);
            operateSceneInstService.addInst(sceneInstId, prodInst);
        }

        return kiteOfferInst;
    }

    private List<KiteBatchAcceptDetailDTO> getBatchAcceptDetails(List<String> importTypes) {
        Example batchExample = Example.builder(KiteBatchAccept.class).selectDistinct("batchId").build();
        batchExample.createCriteria().andEqualTo("statusCd", BatchAcceptStatusEnum.STATUS_CD_1400.getStatusCd())
            .andIn("importType", importTypes);
        List<KiteBatchAccept> batchAccepts = kiteBatchAcceptMapper.selectByExample(batchExample);
        List<String> batchIds = batchAccepts.stream().map(kiteBatchAccept -> kiteBatchAccept.getBatchId().toString())
            .collect(Collectors.toList());
        if (KiteListUtils.isEmpty(batchIds)) {
            return Lists.newArrayList();
        }
        AtomicReference<String> curBatchId = new AtomicReference<>("");
        AtomicReference<String> random = new AtomicReference<>("");
        AtomicReference<List<KiteBatchAcceptDetailDTO>> executeList = new AtomicReference<>(null);
        String num = DcSystemParamCache.getDcParamVal("COP_BATCH_ACCEPT_JOB_NUM");
        if (KiteStringUtils.isEmpty(num)) {
            num = "200";
        }
        // 找出要处理的批次
        for (String batchId : batchIds) {
            Integer detailCount = kiteBatchAcceptDetailMapper
                .listCommitBatchDetailCount(Long.valueOf(batchId), BatchAcceptStatusEnum.CHECK_STATUS_1000.getStatusCd(),
                    StatusConst.NOT_STATUSCD);
            if (detailCount <= 0) {
                continue;
            }
            // 拿到批数据的新的随机数，并且更新到批数据中
            // 取数据时要控制事务，取完的数据不允许其它程序再取了
            String tempRandom = BatchAcceptUtil.createRandom();
            try {
                String finalNum = num;
                TransactionUtils.executeNew(
                    () -> kiteBatchAcceptDetailMapper.updateRandom(tempRandom, batchId, Integer.parseInt(finalNum), BatchAcceptStatusEnum.CHECK_STATUS_1000.getStatusCd()));
            }
            catch (Exception e) {
//                e.printStackTrace();
                ErrorConsts.BUSI_COMMON_ERROR.throwOut("更新随机数失败");
            }
            executeList.set(kiteBatchAcceptDetailMapper.listExecuteDetails(batchId, tempRandom));
            //拿到需要处理的数据就中止循环
            if (!KiteListUtils.isEmpty(executeList.get())) {
                random.set(tempRandom);
                curBatchId.set(batchId);
                break;
            }
        }
        return executeList.get();
    }

    private List<Map<String, Object>> converKeyToUpperCase(List<Map<String, Object>> userInfoList) {
        List<Map<String, Object>> newUserInfoList = Lists.newArrayList();
        for (Map<String, Object> stringObjectMap : userInfoList) {
            Map<String, Object> newUserInfo =new HashMap<>();
            Iterator<String> it = stringObjectMap.keySet().iterator();
            while (it.hasNext()) {
                String key = it.next();
                if (KiteStringUtils.equals("serial_number", key)) {
                    newUserInfo.put("MEM_SERIAL_NUMBER", stringObjectMap.get(key));
                }
                else {
                    newUserInfo.put(key.toUpperCase(), stringObjectMap.get(key));
                }

            }
            newUserInfoList.add(newUserInfo);
        }
        return newUserInfoList;
    }
}
